package org.osgiutils.common.log;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;

/**
 * A implementation of the LogService interface. Log messages are either
 * forwarded to an instance of the LogService registered with the service
 * registry, or are (optionally) printed to the system console when no other
 * LogService instance is available.
 * 
 * NB: This class is NOT intended to be registered as a service itself. Doing so
 * may result in an infinite loop.
 * 
 * @author Neil Bartlett
 */
public class LogTracker extends ServiceTracker implements LogService {
	private final boolean useSystemOut;

	public LogTracker(BundleContext context) {
		this(context, true);
	}

	public LogTracker(BundleContext context, boolean useSystemOut) {
		super(context, LogService.class.getName(), null);
		this.useSystemOut = useSystemOut;
	}

	public void log(int level, String message) {
		log(null, level, message, null);
	}

	public void log(int level, String message, Throwable exception) {
		log(null, level, message, exception);
	}

	public void log(ServiceReference sr, int level, String message) {
		log(sr, level, message, null);
	}

	public void log(ServiceReference sr, int level, String message,
			Throwable exception) {
		LogService log = (LogService) getService();
		if (log == null && useSystemOut) {
			String formattedMessage = format(sr, level, message, exception);
			PrintStream out = (level == LogService.LOG_ERROR) ? System.err
					: System.out;
			out.println(formattedMessage);
		} else {
			log.log(sr, level, message, exception);
		}
	}

	protected String format(ServiceReference sr, int level, String message,
			Throwable exception) {
		StringBuffer buf = new StringBuffer();
		buf.append('[').append(sr).append("] ");

		String levelStr;
		switch (level) {
		case LogService.LOG_DEBUG:
			levelStr = "DEBUG";
			break;
		case LogService.LOG_INFO:
			levelStr = "INFO";
			break;
		case LogService.LOG_WARNING:
			levelStr = "WARNING";
			break;
		case LogService.LOG_ERROR:
			levelStr = "ERROR";
			break;
		default:
			levelStr = "?????";
		}

		buf.append(levelStr).append(": ");
		buf.append(message);
		if (exception != null) {
			StringWriter writer = new StringWriter();
			exception.printStackTrace(new PrintWriter(writer));
			buf.append('\n').append(writer.getBuffer());
		}
		return buf.toString();
	}
}
